import { Role as RoleEntity } from '@/entity/Role';
import { Permission as PermissionEntity } from '@/entity/Permission';
import { ResponseBody, ResponseCode } from '@/utils/ResponseCode';
import {
  Body,
  Controller,
  Delete,
  Get,
  HttpException,
  HttpStatus,
  Param,
  Post,
  Put,
  Query,
  Req,
  Session,
  UseGuards,
} from '@nestjs/common';
import {
  CreateRoleRequest,
  GetRolesRequest,
  RoleModifyRequest,
} from './dto/request.dto';
import { RoleService } from './role.service';
import { createPermissionTreeByPath } from '@/utils/createPermissionTreeByPath';
import { UserService } from '../user/user.service';
import { Request as HttpRequest } from 'express';
import { SessionType } from '@/types';
import { SessionGuard } from '@/guard/session.guard';

@UseGuards(SessionGuard)
@Controller('role')
export class RoleController {
  constructor(
    private readonly roleService: RoleService,
    private readonly userService: UserService,
  ) {}

  @Get()
  async getRoles(
    @Query() query: GetRolesRequest,
    @Req() request: HttpRequest,
    @Session() session: SessionType,
  ) {
    // 接口鉴权
    await this.userService.verifyPermission(request, session.username);
    const { current, pageSize, ...findWhere } = query;
    const { total, list } = await this.roleService.findAllAndCount(findWhere, {
      current,
      pageSize,
    });
    return new ResponseBody<{
      total: number;
      list: RoleEntity[];
    }>({
      data: { total, list },
      message: '获取角色列表成功',
    });
  }

  @Get(':id')
  async getRoleById(
    @Param('id') roleId: number,
    @Req() request: HttpRequest,
    @Session() session: SessionType,
  ) {
    // 接口鉴权
    await this.userService.verifyPermission(request, session.username);
    const roleEntity = await this.roleService.findRoleWithPermission(roleId);
    // 使用map是为了防止有相同的 permission
    const permissionIdMap: {
      [key: number]: PermissionEntity;
    } = {};

    roleEntity.rolePermissions.reduce((prev, { permission }) => {
      permissionIdMap[permission.id] = permission;
      return prev;
    }, permissionIdMap);

    const permissionTree = createPermissionTreeByPath(
      Object.values(permissionIdMap),
    );

    return new ResponseBody<any>({
      data: {
        ...roleEntity,
        rolePermissions: undefined,
        permissionTree,
        permissionList: Object.values(permissionIdMap),
      },
      message: '获取角色信息成功',
    });
  }

  @Post()
  async createRole(
    @Body() requestBody: CreateRoleRequest,
    @Req() request: HttpRequest,
    @Session() session: SessionType,
  ) {
    // 接口鉴权
    await this.userService.verifyPermission(request, session.username);
    const { name, znName, permissionIds = [] } = requestBody;
    const oldRoleEntity = await this.roleService.findOneBy({ name });
    if (oldRoleEntity) {
      return new ResponseBody({
        message: '已经存在相同英文名角色',
        code: ResponseCode.Fail,
      });
    }

    try {
      const resultSetId = await this.roleService.createRole(
        { name, znName },
        permissionIds,
      );
      return new ResponseBody({
        message: '创建角色成功',
        data: resultSetId,
      });
    } catch (error) {
      console.log(error);
      // 事务抛出错误的兜底
      throw new HttpException(
        {
          message: error,
          code: ResponseCode.Fail,
          data: null,
        },
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

  @Put(':id')
  async updateRoleById(
    @Param('id') roleId: number,
    @Body() requestBody: RoleModifyRequest,
    @Req() request: HttpRequest,
    @Session() session: SessionType,
  ) {
    // 接口鉴权
    await this.userService.verifyPermission(request, session.username);
    const { permissionIds, ...toUpdateRole } = requestBody;
    try {
      await this.roleService.updateRoleWithPermission(
        roleId,
        { ...toUpdateRole },
        permissionIds || [],
      );
      return new ResponseBody('更新角色信息成功');
    } catch (error) {
      // 事务抛出错误的兜底
      throw new HttpException(
        {
          message: error,
          code: ResponseCode.Fail,
          data: null,
        },
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

  @Delete(':id')
  async deleteRoleById(
    @Param('id') roleId: number,
    @Req() request: HttpRequest,
    @Session() session: SessionType,
  ) {
    // 接口鉴权
    await this.userService.verifyPermission(request, session.username);
    const roleEntity = await this.roleService.findOneBy({ id: roleId });
    if (roleEntity.isSuper === '1') {
      return new ResponseBody({
        code: ResponseCode.Fail,
        message: '超管无法删除',
      });
    }
    try {
      await this.roleService.deleteRoleById(roleId);
      return new ResponseBody('删除成功');
    } catch (error) {
      // 事务抛出错误的兜底
      throw new HttpException(
        {
          message: error,
          code: ResponseCode.Fail,
          data: null,
        },
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }
}
